package com.zhss.demo.register.server;

import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 服务注册表
 *
 * @author zhonghuashishan
 */
public class ServiceRegistry {

    public static final Long RECENTLY_CHANGED_ITEM_CHECK_INTERVAL = 30000L;
    public static final Long RECENTLY_CHANGED_ITEM_EXPIRED = 3 * 60 * 1000L;
    /**
     * 注册表是一个单例
     */
    private static ServiceRegistry instance = new ServiceRegistry();

    /**
     * 获取服务注册表的单例实例
     *
     * @return
     */
    public static ServiceRegistry getInstance() {
        return instance;
    }

    /**
     * 最近3分钟变化的服务实例
     */
    private static LinkedList<RecentlyChangeServiceInstance> recentlyChangeServiceInstancesQueue = new LinkedList<RecentlyChangeServiceInstance>();

    /**
     * 服务注册表的锁
     */
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

    private ServiceRegistry() {
        RecentlyChangeQueueMonitor recentlyChangeQueueMonitor = new RecentlyChangeQueueMonitor();
        recentlyChangeQueueMonitor.setDaemon(true);
        recentlyChangeQueueMonitor.start();
    }

    /**
     * 核心的内存数据结构：注册表
     * <p>
     * Map：key是服务名称，value是这个服务的所有的服务实例
     * Map<String, ServiceInstance>：key是服务实例id，value是服务实例的信息
     */

    private Map<String, Map<String, ServiceInstance>> registry =
            new ConcurrentHashMap<String, Map<String, ServiceInstance>>();

    /**
     * 服务注册
     *
     * @param serviceInstance 服务实例
     */
    public void register(ServiceInstance serviceInstance) {
        try {
            writeLock.lock();
            Map<String, ServiceInstance> serviceInstanceMap =
                    registry.get(serviceInstance.getServiceName());
            if (serviceInstanceMap == null) {
                serviceInstanceMap = new ConcurrentHashMap<String, ServiceInstance>();
                registry.put(serviceInstance.getServiceName(), serviceInstanceMap);
            }
            //插入服务注册表中
            serviceInstanceMap.put(serviceInstance.getServiceInstanceId(),
                    serviceInstance);
            //构建一个服务变化表
            RecentlyChangeServiceInstance recentlyChangeServiceInstance = new RecentlyChangeServiceInstance(serviceInstance, System.currentTimeMillis(), ServiceInstanceOperation.REGISTER);
            //插入服务变化表中
            recentlyChangeServiceInstancesQueue.add(recentlyChangeServiceInstance);
            System.out.println("服务实例【" + serviceInstance + "】，完成注册......");
            System.out.println("注册表：" + registry);
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 获取服务实例
     *
     * @param serviceName       服务名称
     * @param serviceInstanceId 服务实例id
     * @return 服务实例
     */
    public ServiceInstance getServiceInstance(String serviceName,
                                              String serviceInstanceId) {
        Map<String, ServiceInstance> serviceInstanceMap = registry.get(serviceName);
        return serviceInstanceMap.get(serviceInstanceId);
    }

    /**
     * 获取整个注册表
     *
     * @return
     */
    public Map<String, Map<String, ServiceInstance>> getRegistry() {
        return registry;
    }

    /**
     * 获取增量注册表
     *
     * @return
     */
    public DeltaRegister getDeltaRegistry() {


        //获取当前register中服务实例的数量
        Long serviceInstancesTotal = 0L;
        for (Map<String, ServiceInstance> instanceMap : registry.values()) {
            serviceInstancesTotal += instanceMap.size();
        }
        DeltaRegister deltaRegister = new DeltaRegister(recentlyChangeServiceInstancesQueue, serviceInstancesTotal);
        return deltaRegister;

    }

    /**
     * 从注册表删除一个服务实例
     *
     * @param serviceName
     * @param serviceInstanceId
     */
    public void remove(String serviceName, String serviceInstanceId) {
        try {
            this.writeLock.lock();
            System.out.println("服务实例【" + serviceInstanceId + "】，从注册表中进行摘除");
            //获取服务名对应的所有服务
            Map<String, ServiceInstance> serviceInstanceMap = registry.get(serviceName);
            //获取将要删除的服务
            ServiceInstance serviceInstance = serviceInstanceMap.get(serviceInstanceId);
            //构建变化的服务实例
            RecentlyChangeServiceInstance recentlyChangeServiceInstance = new RecentlyChangeServiceInstance(serviceInstance, System.currentTimeMillis(), ServiceInstanceOperation.REMOVE);
            //将变化的服务塞入最近变化队列
            recentlyChangeServiceInstancesQueue.add(recentlyChangeServiceInstance);
            serviceInstanceMap.remove(serviceInstanceId);
        } finally {
            this.writeLock.unlock();
        }
    }


    /**
     * 最近变化的服务实例
     */
    class RecentlyChangeServiceInstance {
        /**
         * 服务实例
         */
        ServiceInstance serviceInstance;
        /**
         * 实例变化时的时间戳
         */
        Long changeTimeStamp;
        /**
         * 服务实例的变化
         */
        String serviceInstanceOperation;

        public RecentlyChangeServiceInstance(ServiceInstance serviceInstance, Long changeTimeStamp, String serviceInstanceOperation) {
            this.serviceInstance = serviceInstance;
            this.changeTimeStamp = changeTimeStamp;
            this.serviceInstanceOperation = serviceInstanceOperation;
        }

        @Override
        public String toString() {
            return "RecentlyChangeServiceImstance{" +
                    "serviceInstance=" + serviceInstance +
                    ", changeTimeStamp=" + changeTimeStamp +
                    ", serviceInstanceOperation='" + serviceInstanceOperation + '\'' +
                    '}';
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            RecentlyChangeServiceInstance recentlyChangeServiceInstance = new RecentlyChangeServiceInstance(serviceInstance, changeTimeStamp, serviceInstanceOperation);
            return recentlyChangeServiceInstance;
        }
    }

    /**
     * 服务操作
     */
    class ServiceInstanceOperation {
        public static final String REGISTER = "REGISTER";
        public static final String REMOVE = "REMOVE";
    }

    /**
     * 监控实例最近变化队列
     * 将超过30s的变化实例移除
     */
    class RecentlyChangeQueueMonitor extends Thread {
        @Override
        public void run() {
            while (true) {
                System.out.println("进行一次拉取");
                try {
                    synchronized (instance) {
                        RecentlyChangeServiceInstance recentlyChangeServiceInstance = null;
                        Long currentTimeStamp = System.currentTimeMillis();
                        while ((recentlyChangeServiceInstance = ((LinkedList<RecentlyChangeServiceInstance>) recentlyChangeServiceInstancesQueue).peek()) != null) {
                            if (currentTimeStamp - recentlyChangeServiceInstance.changeTimeStamp > RECENTLY_CHANGED_ITEM_CHECK_INTERVAL) {
                                System.out.println(recentlyChangeServiceInstance + "被拉取走了");
                                recentlyChangeServiceInstancesQueue.removeFirst();
                            }
                        }
                    }
                    Thread.sleep(RECENTLY_CHANGED_ITEM_EXPIRED);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }
    }

    /**
     * 加读锁
     */
    public void readLock() {
        readLock.lock();
    }

    /**
     * 释放读锁
     */
    public void unReadLock() {
        readLock.unlock();
    }
}
